package md.cm.base;

import lombok.*;
import md.cm.geography.Adminunit;
import md.cm.unit.Unit;
import org.fjsei.yewu.aop.hibernate.AdminunitBinder;
import org.fjsei.yewu.filter.NodeName;
import org.fjsei.yewu.util.Tool;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.search.engine.backend.types.Aggregable;
import org.hibernate.search.engine.backend.types.ObjectStructure;
import org.hibernate.search.engine.backend.types.Projectable;
import org.hibernate.search.engine.backend.types.Sortable;
import org.hibernate.search.mapper.pojo.automaticindexing.ReindexOnUpdate;
import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.PropertyBinderRef;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.*;

import jakarta.persistence.*;
import java.util.UUID;

//外部管理的数据源，如何对接？我方只能读的，同步对方数据源的更新，高层次的接口，频率一致性保证；
//假如是直接用接口/微服务/Rest方式，那么存储是在对方，搜索引擎也是在对方，前端只是直接连接调用对方的API接口？授权使用问题；或者后端二传手中继。
//但若失去外部系统访问授权可保障性；只能自己拷贝数据/一部分我方用到的大数据，面临更新滞后和不一致问题？本地建库表no是外部关键ID标识，id是我方内部1:1对应ID。
//暂时去掉 @Table(uniqueConstraints={@UniqueConstraint(columnNames={"no"}) })

/** 公民个人表
 * Person里面有的不见得一定就会在Unit表里面找到一个Unit的吧, User账户表可以直接对接Person表。
 * 原本计划全部从监察平台录入个人表和Company表的数据管辖权； 保留？本平台检验方可以自己录入维护一部分的公司或个人信息：重复融合，数据真实性的负责机构?。
 * Unit是我平台单位概念。company person两个只能二选一而且都是1对1关联Unit的。Person是外部管理数据源头。允许Person没有关联上Unit实体。
 * */

@Getter
@Setter
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder=true)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL, region ="Slow")
@Indexed
public class Person implements PersonPi,NamePi, NodeName {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private UUID id;

    /**人名 奇了？  ’延平区文体路143号1单元全体业主‘
     */
    //@GenericField(name = "name_sort",sortable = Sortable.YES)
    //@KeywordField(name = "name_sort",sortable = Sortable.YES)     用处多大啊？
    @FullTextField
    @Column(length = 40)
    private String name;    //UNT_NAME； 姓名还是可能出现变化的。


    /**身份证号码 UNT_ORG_COD； 通用与 (Unit:)社会信用代码：USE_UNT_ORGCOD 合用可以。两个代码不冲突重复。
      不可重复！ 不变动的no终身跟随。
     * */
    //@FullTextField(analyzer = "ngram_analyzer")    有意义吗?，浪费存储空间！
    @KeywordField(sortable = Sortable.YES)
    @Column(unique = true)
    private String no;


    /**外部来源
     * 证件上记载的地址。身份证地址
     配合Adminunit把ES上相应本字段改造为包含了区域名的全文本地址，国内应用：中国两个字前缀省略掉。
     */
    @FullTextField
    @Column(length = 150)
    private String address;  //不用于搜索PersonES；不轻易改变地址。

    /**配合地址的 区域代码: 很多同名字，户籍管理归属地来区分的。
     * @IndexedEmbedded(structure= ObjectStructure.NESTED) 嵌套模式｛性能差的，保留严格对象｝, 但默认是.FLATTENED
     * @IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
     * */
//    @IndexedEmbedded(structure= ObjectStructure.FLATTENED)
    //@IndexingDependency(reindexOnUpdate = ReindexOnUpdate.DEFAULT)      //不关心区域id对应的Adminunit内容修改，只能手动更新。
    @PropertyBinding(binder = @PropertyBinderRef(type = AdminunitBinder.class))
    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn(name = "aid")     //去掉nullable=false，会导致初始化表缺省aid=0
    private Adminunit ad;       //行政区划; 有些同步来源就没指出地区代码。同步生成的需要后期人工合并地址！。


    private Double lat;  //纬度 ;精确到小数点后6位可达约1米精度。 ？综合考虑地址所有关联多个设备原始数据，同步时期还未人工确认以最新数据为准。
    private Double lon;  //经度  前面的是纬度,后面的是经度； 其它同步来源不一定有Geo: tb_unt_mge  jc_unt_mge有。

    /**可以体现行政区划的： 方便定位。
     *  当前实际上的地址，最新居住的地址。
    PersonEs设计成这样｛id, name, pos{Address.id}, extadr扩展地址文本串[门牌号]｝pos可提前搜并选定id过滤！随后进一步extadr是搜索；
     *  */
  //  @ManyToOne(fetch= FetchType.LAZY)
 //   private Address pos;    //多对1，；地理定位 方式。
    /**扩展地址文本串[门牌号] 更能精确定位快递地址
     * */
  //  private String  extadr;      //目前居住地址： 配合pos扩充详细。

    /**(Unit:)使用单位联系人：UNT_LKMEN就一个人还需要分身的？;, 个人的：不需要再设字段；
     * 使用单位联系手机：UNT_MOBILE,
     * 一般个人是使用单位, 类似 字段Eqp.的 设备联系人手机号，USE_MOBILE;
     * 不是多个电话号码的，可以直接equal(==''), 假如多个，影响较大！ 多个电话号码应该放入说明字段 desc? memo? extJson{,:tel2};
     * 个人只需要手机号码：可发送短信的。
     * 对比与Company的搜索模型多出个 注册手机号码的 可搜索需求特征，企业按照名称足够搜索定位，个人重复姓名太多了。
     * */
    @KeywordField      //只能单一个手机号码， 不允许多个电话号码拼凑的？国内固定电话+区号 0591xxxM
    private String phone;       //个人手机号，默认一个手机号码，假如多个,逗号分隔 ,， 分隔符? 前端强化输入约束[][]后端归一化。

    //@KeywordField(projectable = Projectable.YES)      还是省略掉吧！
    private String gender;        //Todo: Enum: 性别 男 女 3:;
    //@FullTextField
    //@KeywordField(name = "occupation_sort",sortable = Sortable.YES, projectable = Projectable.YES, aggregable = Aggregable.YES)
    private String occupation;     //职业, 描述性的字符串，x，


    //若需要双向的1 ：1关系，关系是Unit类维护； 就把下面俩个行添加上。[应用系统领域]太多了？ 很多的业务很多模块插入关联关系字段？
    /**本来不用这个字段的， 【因为】Hibernate Search自动更新而被动添加！
     * */
    @OneToOne(mappedBy = "person")
    private Unit unit;


/*    public void copyAs(UntMge untMge){
        //依照老旧平台来比较修改。
        if(no==null || !no.equals(untMge.getUNT_ORG_COD()) )               no=untMge.getUNT_ORG_COD();
        if(phone==null || !phone.equals(untMge.getUNT_MOBILE()) )       phone=untMge.getUNT_MOBILE();
        if(origadr ==null || !origadr.equals(untMge.getUNT_ADDR()) )     origadr =untMge.getUNT_ADDR();
    };*/

    @Transient
    public String address(){
        if(null!=ad)
            return(ad.getPrefix()+" "+address);
        else
            return address;
    }
}

